﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TestConsoleApp
{
    public class TestAPM
    {
        public static void Test()
        {
            Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} main thread {Thread.CurrentThread.ManagedThreadId}");
            var fs = new MyAsyncFileSteam();
            var bs = new byte[10];
            var asyncRes2 = fs.BeginRead(bs, 0, 10, asyncRes =>
            {
                Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} 异步回调 thread {Thread.CurrentThread.ManagedThreadId}");
            }, new { Name = "小明" });
            //asyncRes2.AsyncWaitHandle.WaitOne();
            Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} main thread {Thread.CurrentThread.ManagedThreadId}");
            //int len = fs.EndRead(asyncRes2);
            //Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} main thread {Thread.CurrentThread.ManagedThreadId} len={len}");
            Console.ReadLine();
        }

    }

    public class MyAsyncFileSteam
    {
        private Dictionary<IAsyncResult, int> _dic = new Dictionary<IAsyncResult, int>();
        public IAsyncResult BeginRead(byte[] arr, int offSet, int length, AsyncCallback asyncCallback, object state)
        {
            var manEventReset = new ManualResetEvent(false);
            var res = new MyAsyncResult(manEventReset, state);
            // 模拟读文件，实际上应该是调用设备IO，读写完成后设备发出DMA中断到CPU，然后再回调用户代码
            ThreadPool.QueueUserWorkItem(_state =>
            {
                // 假设最多文件只有一个字节
                for (var i = offSet; i < offSet + 1; i++)
                {
                    arr[offSet] = 1;
                }
                //模拟耗时
                Thread.Sleep(3000);
                _dic.Add(res, 1);
                manEventReset.Set();
                res.SetCompleted();
                ThreadPool.QueueUserWorkItem(_state2 =>
                {
                    asyncCallback(res);
                });
            });
            return res;
        }

        public int EndRead(IAsyncResult asyncResult)
        {
            asyncResult.AsyncWaitHandle.WaitOne();
            return _dic[asyncResult];
        }

        public class MyAsyncResult : IAsyncResult
        {
            private readonly WaitHandle waitHandle;
            private readonly object state;
            private bool isCompleted = false;

            public MyAsyncResult(WaitHandle waitHandle, object state)
            {
                this.waitHandle = waitHandle;
                this.state = state;
            }

            internal void SetCompleted()
            {
                isCompleted = true;
            }
            public bool IsCompleted => isCompleted;

            public WaitHandle AsyncWaitHandle => waitHandle;

            public object AsyncState => state;

            public bool CompletedSynchronously => isCompleted;
        }
    }
}
